import os
import pytz
import logging
from typing import Any, Dict, Union
from logging.handlers import TimedRotatingFileHandler


_LOGGERS = {}


class Util(object):
    """
    日志函数封装
    """
    tz: Any = pytz.timezone("Asia/Shanghai")
    log_levels: Dict[str, Any] = {
        'debug': logging.DEBUG,
        'info': logging.INFO,
        'warnging': logging.WARNING,
        'error': logging.ERROR,
        'critical': logging.CRITICAL
    }

    @classmethod
    def pyfile_logger(
        cls,
        pyfile_name: str,
        level: str="info",
        log_path: Union[None, str]=None
    ) -> logging.Logger:
        """
        1.为python文件创建和配置记录器
        2.日志文件将存储在同一目录中的“log”目录中
        3.目录使用python文件名称
        4.引发异常：如果无法创建或访问日志目录。
        ：param pyfile_name: 要为其创建记录器的python文件的名称
        ：param level: 记录器设置的日志记录级别, 默认值为“info”
        ：param log_path: 日志文件应存储的路径, 可为空
        ：return: 已配置的日志记录, 记录器对象。
        """
        if log_path:
            dirname = log_path
        else:
            perfix = os.path.dirname(pyfile_name)
            dirname = os.path.join(perfix, "log")
        basename = os.path.basename(pyfile_name).replace(".py", "")
        filename = os.path.join(dirname, basename)

        # 检查文件夹是否存在，如果不存在，则创建文件夹
        if not os.path.exists(filename):
            os.makedirs(filename)
        return cls.init_log(basename, level, filename)

    @classmethod
    def init_log(
        cls,
        tag: str,
        level: str,
        filename: Union[str, None]=None,
        backup_count: int=3
    ) -> logging.Logger:
        """
        1.初始化记录器
        2.创建日志处理器
        ：param标签：记录器的唯一标识符
        ：param level：为记录器设置的日志记录级别, 选项包括“调试”、“信息”、“警告”、“错误”和“严重”
        ：param文件名：可选；日志文件的基本名称。如果提供, 日志将写入文件。如果没有，日志将输出到控制台
        ：param backup_count：可选 要保留的备份日志文件的数量，默认三天的数据, 仅在提供“filename”时适用
        ：return：记录器实例
        """
        # 缓存记录器实例
        if _LOGGERS.get(tag):
            return _LOGGERS.get(tag)

        outputs = [
            "[%(asctime)s | ",
            "%(filename)s, ",
            "%(funcName)s, ",
            "line %(lineno)d | ",
            "%(levelname)s] ",
            "%(message)s",
        ]
        formatter = logging.Formatter("".join(outputs))
        logger = logging.getLogger(tag)
        logger.setLevel(cls.log_levels[level])

        if filename:
            name = os.path.join(filename, f'{tag}.log')
            hand = logging.handlers.TimedRotatingFileHandler(
                name,
                when='midnight',
                backupCount=backup_count
            )
        else:
            hand = logging.StreamHandler()

        hand.setLevel(cls.log_levels["debug"])
        hand.setFormatter(formatter)
        logger.addHandler(hand)
        _LOGGERS.update({tag: logger})

        return logger
